/************************************************************************
Copyright (c) 2010, 2013, C.R. All rights reserved. 

E-mail: crtoyou@gmail.com; crtoyou@163.com

You can redistribute it and/or modify it under the terms of the
GNU Lesser General Public License as published by the
Free Software Foundation version 3 of the License.

This source code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. if not, write to the Free Software Foundation, Inc., 
51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
************************************************************************/

#ifndef __CR_DATA_MSG_PACKET_DEF_H__
#define __CR_DATA_MSG_PACKET_DEF_H__

#include <crdefine.h>
#include <crdebug.h>

namespace cr {

struct packhead0_t
{
	int32 len;

	enum { max_len = 512 * 1024 * 1024 }; //512MB < INT_MAX(2GB)
};

struct packhead1_t
{
	int16 len;
	int16 msg;

	enum { max_len = 16 * 1024 }; //16KB < SHRT_MAX(32KB)
};

struct packhead2_t
{
	int16 len; 
	int8  msg;
	int8  chk;

	enum { max_len = 16 * 1024 }; //16KB < SHRT_MAX(32KB)
};

struct packhead3_t
{
	int32 len;
	int16 rnd;
	int8  msg;
	int8  chk;

	enum { max_len = 64 * 1024 * 1024 }; //64MB < INT_MAX(2GB)
};

template <class type_packhead>
struct pack_t
{
	type_packhead head;
	char payload[1];

	enum { unexpected_size = 2U * 1024 * 1024 * 1024 }; //1GB < INT_MAX(2GB)
};

template <class type_packhead>
inline bool prepack(const size_t loadlen, size_t& packsize, int& offset)
{
	offset = offsetof(pack_t<type_packhead>, payload);
	packsize = offset + loadlen;
	if (packsize >= type_packhead::max_len)
		return false;
	return true;
}
template <class type_packhead>
inline bool unpack(pack_t<type_packhead>* pack, void*& payload, size_t& loadlen)
{
	ASSERT(pack);
	if (pack->head.len < offsetof(pack_t<type_packhead>, payload)
		|| pack->head.len >= type_packhead::max_len)
		return false;
	payload = &pack->payload[0];
	loadlen = pack->head.len - offsetof(pack_t<type_packhead>, payload);
	return true;
}

}//namespace

#endif //__CR_DATA_MSG_PACKET_DEF_H__